package org.zhangchao.poi.excel.operate;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.zhangchao.poi.excel.common.ExcelEnum;
import org.zhangchao.poi.excel.common.template.ExcelTemplateParam;
import org.zhangchao.poi.excel.create.ExcelCreatable;
import org.zhangchao.poi.excel.process.ExcelProcessable;

public abstract class ExcelOperate implements ExcelProcessable, ExcelCreatable {

	/** Workbook */
	protected Workbook workbook;

	/** Sheet */
	private Sheet sheet;
	
	/** sheetName */
	private String sheetName;

	public ExcelOperate(ExcelEnum type) throws Exception {
		if (ExcelEnum.TYPE2003.equals(type)) {
			workbook = new HSSFWorkbook();
		} else if (ExcelEnum.TYPE2007.equals(type)) {
			workbook = new XSSFWorkbook();
		} else {
			throw new Exception("构造Excel解析器失败：传入的类型不对！");
		}
	}

	public ExcelOperate(String fileName) throws InvalidFormatException, IOException {
		File file = new File(fileName);
		workbook = WorkbookFactory.create(file);
	}
	
	public ExcelOperate(File file) throws InvalidFormatException, IOException {
		workbook = WorkbookFactory.create(file);
	}

	public ExcelOperate(InputStream inp) throws InvalidFormatException,
			IOException {
		workbook = WorkbookFactory.create(inp);
	}

	//@Override
	public void processOneSheet(int sheetIndex) throws Exception {
		// 接口统一sheet从0开始
		if (sheetIndex < 0) {
			throw new Exception("目标sheet索引至少要从0开始。");
		}
		Sheet sheet = workbook.getSheetAt(sheetIndex);
		Iterator<Row> rows = sheet.iterator();
		while (rows.hasNext()) {
			Row row = rows.next();
			if (!isBlankRow(row)) {
				processRow(row);
			}
		}
	}

	//@Override
	public void processAllSheets() throws Exception {
		for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
			processOneSheet(i);
		}
	}

	//@Override
	public abstract void processRow(Row row);

	//@Override
	public void stop() throws IOException {

	}

	//@Override
	public Sheet createSheet() {
		sheet = workbook.createSheet();
		return sheet;
	}

	//@Override
	public Sheet createSheet(String sheetname) {
		sheet = workbook.createSheet(sheetname);
		return sheet;
	}

	//@Override
	public Row createRow(int i) {
		if (null == sheet) {
			if(null == sheetName || "".equals(sheetName)) {
				createSheet();
			} else {
				createSheet(sheetName);
			}
		}
		Row row = sheet.createRow(i);
		createRow(row);
		return row;
	}
	
	//@Override
	public Row copyRow(int i, Row row) {
		if (null == sheet) {
			if(null == sheetName || "".equals(sheetName)) {
				createSheet();
			} else {
				createSheet(sheetName);
			}
		}
		Row newRow = sheet.createRow(i);
		//设置行高
		newRow.setHeightInPoints(row.getHeightInPoints());
		return newRow;
	}

	//@Override
	public abstract void createRow(Row row);
	
	//@Override
	public abstract void create();
	
	//@Override
	public abstract ExcelTemplateParam getExcelTemplateaParam();
	
	//@Override
	public void create(String sheetName) {
		this.sheetName = sheetName;
		create();
	}

	//@Override
	public Cell createCell(Row row, int i) {
		Cell cell = row.createCell(i);
		return cell;
	}
	
	//@Override
	public Cell copyCell(Row row, int i, Cell cell) {
		Cell newCell = row.createCell(i);
		//设置样式
		CellStyle cellStyle = workbook.createCellStyle();
		cellStyle.cloneStyleFrom(cell.getCellStyle());
		newCell.setCellStyle(cellStyle);
		//设置值
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_BLANK:
			newCell.setCellValue("");
			break;
		case Cell.CELL_TYPE_BOOLEAN:
			newCell.setCellValue(cell.getBooleanCellValue());
			break;
		case Cell.CELL_TYPE_FORMULA:
			newCell.setCellValue(cell.getCellFormula());
			break;
		case Cell.CELL_TYPE_NUMERIC:
			newCell.setCellValue(cell.getNumericCellValue());
			break;
		case Cell.CELL_TYPE_STRING:
			newCell.setCellValue(cell.getStringCellValue());
			break;
		default:
			break;
		}
		return newCell;
	}
	
	//@Override
	public void handelMergedRegion(List<CellRangeAddress> craList) {
		for (CellRangeAddress cra :craList) {
			sheet.addMergedRegion(cra);
		}
	}

	//@Override
	public void write(OutputStream stream) throws IOException {
		workbook.write(stream);
		stream.close();
	}

	private boolean isBlankRow(Row row) {
		boolean b = true;
		for (int i = 0; i < row.getLastCellNum(); i++) {
			Cell cell = row.getCell(i);
			if (null != getCellValue(cell)) {
				b = false;
			}
		}
		return b;
	}

	private Object getCellValue(Cell cell) {
		Object o = null;
		switch (cell.getCellType()) {
		case Cell.CELL_TYPE_BLANK:
			o = "";
			break;
		case Cell.CELL_TYPE_BOOLEAN:
			o = cell.getBooleanCellValue();
			break;
		case Cell.CELL_TYPE_FORMULA:
			o = cell.getCellFormula();
			break;
		case Cell.CELL_TYPE_NUMERIC:
			o = (int) cell.getNumericCellValue();
			break;
		case Cell.CELL_TYPE_STRING:
			o = cell.getStringCellValue();
			break;
		default:
			o = null;
			break;
		}
		return o;
	}

	public String getSheetName() {
		return sheetName;
	}

	public void setSheetName(String sheetName) {
		this.sheetName = sheetName;
	}
	
}
